"""
系统监控模块
"""
import psutil
import time
from typing import Dict, Any
from sqlalchemy.engine import Engine
from sqlalchemy import event
import threading
from functools import wraps
from flask import g
import os
import redis
from datetime import datetime
from collections import deque
from threading import Lock
import logging

logger = logging.getLogger(__name__)

class SystemMonitor:
    """系统监控类"""

    def __init__(self):
        self.request_times = deque(maxlen=1000)  # 最多保存1000个请求时间
        self._lock = Lock()
        self.metrics = {
            'cache_hits': 0,
            'cache_misses': 0,
            'error_count': 0,
            'total_requests': 0
        }
        self.db_query_times = []
        self._start_monitoring()

    def _start_monitoring(self):
        """启动后台监控线程"""

        def monitor():
            while True:
                self.collect_metrics()
                time.sleep(60)  # 每分钟收集一次

        thread = threading.Thread(target=monitor, daemon=True)
        thread.start()

    def collect_metrics(self) -> Dict[str, Any]:
        """收集系统指标"""
        try:
            # 使用interval=0.1来获取更准确的CPU使用率
            cpu_percent = psutil.cpu_percent(interval=0.1)
            
            return {
                'cpu': round(cpu_percent, 1),  # 保留一位小数
                'memory': round(psutil.virtual_memory().percent, 1),
                'disk': round(psutil.disk_usage('/').percent, 1),
                'error_rate': self.metrics['error_count'] / max(self.metrics['total_requests'], 1),
                'cache_hit_rate': self.metrics['cache_hits'] / 
                                max(self.metrics['cache_hits'] + self.metrics['cache_misses'], 1)
            }
        except Exception as e:
            logger.error(f"收集系统指标失败: {str(e)}")
            return {}

    def start_request(self):
        """开始请求计时"""
        return time.time()
    
    def end_request(self, start_time):
        """结束请求计时"""
        duration = (time.time() - start_time) * 1000  # 转换为毫秒
        with self._lock:
            self.request_times.append(duration)
            self.metrics['total_requests'] += 1
    
    def get_average_response_time(self):
        """获取平均响应时间"""
        with self._lock:
            return sum(self.request_times) / len(self.request_times) if self.request_times else 0
    
    def get_total_requests(self):
        """获取总请求数"""
        return self.metrics['total_requests']
    
    def get_recent_request_times(self, n=10):
        """获取最近n个请求的处理时间"""
        with self._lock:
            return list(self.request_times)[-n:]
    
    def record_cache_hit(self):
        """记录缓存命中"""
        with self._lock:
            self.metrics['cache_hits'] += 1
    
    def record_cache_miss(self):
        """记录缓存未命中"""
        with self._lock:
            self.metrics['cache_misses'] += 1
    
    def record_error(self, error_type=None):
        """记录错误"""
        with self._lock:
            self.metrics['error_count'] += 1
            if error_type:
                logger.error(f"系统错误: {error_type}")
    
    def get_health_status(self) -> Dict[str, Any]:
        """获取系统健康状态"""
        try:
            cpu_percent = psutil.cpu_percent(interval=1)
            memory = psutil.virtual_memory()
            disk = psutil.disk_usage('/')
            
            status = 'healthy'
            if cpu_percent > 80 or memory.percent > 80 or disk.percent > 80:
                status = 'warning'
            if cpu_percent > 90 or memory.percent > 90 or disk.percent > 90:
                status = 'critical'
            
            return {
                'status': status,
                'metrics': {
                    'cpu': cpu_percent,
                    'memory': memory.percent,
                    'disk': disk.percent,
                    'error_rate': self.metrics['error_count'] / max(self.metrics['total_requests'], 1)
                }
            }
        except Exception as e:
            logger.error(f"获取健康状态失败: {str(e)}")
            return {'status': 'error', 'error': str(e)}


class DatabaseMonitor:
    """数据库监控类"""

    def __init__(self, engine: Engine):
        self.engine = engine
        self.stats = {
            'active_connections': 0,
            'total_queries': 0,
            'slow_queries': 0,
            'avg_query_time': 0
        }
        self._lock = Lock()
        self.setup_listeners()

    def setup_listeners(self):
        """设置数据库事件监听器"""

        @event.listens_for(self.engine, 'checkout')
        def receive_checkout(dbapi_connection, connection_record, connection_proxy):
            self.stats['active_connections'] += 1

        @event.listens_for(self.engine, 'checkin')
        def receive_checkin(dbapi_connection, connection_record):
            self.stats['active_connections'] -= 1

        @event.listens_for(self.engine, 'before_cursor_execute')
        def before_cursor_execute(conn, cursor, statement, parameters, context, executemany):
            conn.info.setdefault('query_start_time', []).append(time.time())

        @event.listens_for(self.engine, 'after_cursor_execute')
        def after_cursor_execute(conn, cursor, statement, parameters, context, executemany):
            total_time = time.time() - conn.info['query_start_time'].pop()
            self.stats['total_queries'] += 1
            self.stats['avg_query_time'] = (
                (self.stats['avg_query_time'] * (self.stats['total_queries'] - 1) + total_time) / 
                self.stats['total_queries']
            )

            # 记录慢查询（超过1秒）
            if total_time > 1:
                self.stats['slow_queries'] += 1

    def get_stats(self) -> Dict[str, Any]:
        """获取数据库统计信息"""
        try:
            with self.engine.connect() as conn:
                self.stats['active_connections'] = len(self.engine.pool._checked_out)
            return self.stats
        except Exception as e:
            logger.error(f"获取数据库统计信息失败: {str(e)}")
            return self.stats


class CacheManager:
    """缓存管理器"""

    def __init__(self, redis_url: str = None):
        self.redis_client = redis.from_url(redis_url) if redis_url else None
        self.local_cache = {}
        self.monitor = SystemMonitor()

    def get(self, key: str, default: Any = None) -> Any:
        """获取缓存值"""
        # 先检查本地缓存
        if key in self.local_cache:
            self.monitor.record_cache_hit()
            return self.local_cache[key]

        # 如果配置了Redis，检查Redis缓存
        if self.redis_client:
            value = self.redis_client.get(key)
            if value is not None:
                self.monitor.record_cache_hit()
                return value

        self.monitor.record_cache_miss()
        return default

    def set(self, key: str, value: Any, timeout: int = None):
        """设置缓存值"""
        self.local_cache[key] = value
        if self.redis_client:
            self.redis_client.set(key, value, ex=timeout)

    def delete(self, key: str):
        """删除缓存"""
        self.local_cache.pop(key, None)
        if self.redis_client:
            self.redis_client.delete(key)


def cache_decorator(timeout: int = 300):
    """缓存装饰器"""

    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            # 生成缓存键
            cache_key = f"{func.__name__}:{str(args)}:{str(kwargs)}"

            # 获取缓存管理器
            cache_manager = g.get('cache_manager')
            if not cache_manager:
                return func(*args, **kwargs)

            # 尝试从缓存获取
            result = cache_manager.get(cache_key)
            if result is not None:
                return result

            # 执行函数并缓存结果
            result = func(*args, **kwargs)
            cache_manager.set(cache_key, result, timeout)
            return result

        return wrapper

    return decorator
